Cours 1 : Exclusion mutuelle
Les processus disposent chacun d'un espace d'adressage protégé inaccessible aux autres processus. Pour communiquer et s'échanger
des données, les processus peuvent utiliser des outils de communications offerts par le système. La manipulation de ces outils
de communication doit se faire dans le respect de règles de synchronisation qui vont assurer que les données échangées entre
les
processus
restent cohérentes et ne sont pas perdues. Un premier problème de synchronisation est celui de l'accès par un ensemble de
processus à une
ressource critique
, c'est-à-dire une
ressource
à un seul point d'accès donc utilisable par un seul processus à la fois.
1 Un exemple simple pour définir le problème
Nous allons mettre en lumière le problème qui peut se poser sur un exemple simple : on considère donc un petit programme de
réservation de place (dans un avion, un train,
).
Réservation :
Si nb_place > 0
alors
Réserver une place
nb_place = nb_place - 1
fsi
Ce programme réservation peut être exécuté par plusieurs processus à la fois (autrement dit, le programme est réentrant).
La variable nb_place, qui représente le nombre de place restant dans l'avion par exemple, est ici une variable d'état du système
(de réservation) On considère l'exécution de deux processus Client_1 et Client_2 (figure 1) : Client_1 est commuté par l'
ordonnanceur
juste après avoir testé la valeur de la variable nb_place (nb_place = 1). Client_2 s'exécute à son tour, teste nb_place qu'il
trouve également égale à 1 et donc effectue une réservation en décrémentant de une unité la variable nb_place. Nb_Place devient
égale à 0. Comme le processus Client_2 a terminé son exécution, Client_1 reprend la main. Comme Client_1 avait trouvé la variable
nb_place comme étant égale à 1 juste avant d'être commuté, il continue son exécution en décrémentant à son tour nb_place.
De ce fait, nb_place devient égale à 1 ce qui est incohérent !!! Une même place a été allouée à deux clients différents !
 |
Fig 1 : Un exemple de concurrence
|
|
La variable nb_place doit être accédée par un seul processus à la fois pour rester cohérente : ici en l'occurrence le processus
Client_1 qui a commencé la réservation en premier. Nb_Place est donc une ressource critique.
Définition : Ressource critique
Une ressource critique est une ressource accessible par un seul processus à la fois.
Définition : Section critique
Le code d'utilisation de la ressource critique s'appelle une section critique. La section critique doit offrir au moins une
propriété essentielle : celle de l'exclusion mutuelle c'est-à-dire assurer qu'effectivement elle ne sera jamais exécutée par
plus d'un processus à la fois. Pour ce faire, la section critique est précédée par un prélude et suivie d'un postlude (le
prélude et le postlude sont du code) qui doivent assurer cette propriété d'exclusion mutuelle.
Définition : Exclusion mutuelle
La propriété d'exclusion mutuelle assure qu'une ressource critique ne peut jamais être utilisée par plus de un processus à
la fois.
Pour garantir l'exclusion mutuelle, il faut donc entourer l'utilisation de la variable nb_place d'un prélude et d'un postlude.
Le prélude prend la forme d'une "protection"qui empêche un processus de manipuler la variable nb_place si un autre processus
le fait déjà. Ainsi le processus Client_2 est mis en attente dès qu'il cherche à accéder à la variable nb_place déjà possédée
par le processus Client_1. Le postlude prend la forme d'une"fin de protection" qui libère la ressource nb_place et la rend
accessible au
processus
Client_2.
2 Réalisation d'une section critique à l'aide des interruptions matérielles
Nous rappelons que le mécanisme sous-jacent au ré
ordonnancement
des processus peut être la survenue d'une interruption horloge. Aussi une solution pour réaliser l'exclusion mutuelle est
de masquer les interruptions dans le prélude et de les démasquer dans le postlude. Ainsi les interruptions sont masquées dès
qu'un processus accède à la
ressource
nb_place et aucun événement susceptible d'activer un autre processus ne peut être pris en compte. Cependant, cette solution
est moyennement satisfaisante car elle empêche l'exécution de tous les processus y compris ceux ne désirant pas accéder à
la
ressource critique
. De plus, le masquage et le démasquage des interruptions sont des opérations réservées au
mode superviseur
et ne sont donc pas accessibles pour les processus utilisateurs.
Une autre solution est d'utiliser un outil de synchronisation offert par le système : les sémaphores.
3 L'outil sémaphore. Utilisation de cet outil pour réaliser l'exclusion mutuelle
3.1 Présentation de l'outil sémaphore
Une sémaphore Sem est une structure système composée d'une file d'attente L de processus et d'un compteur K, appelé niveau
du sémaphore et contenant initialement une valeur Val. Cette structure ne peut être manipulée que par trois opérations P(Sem),
V(Sem) et Init(Sem, Val). Une propriété im
port
ante de ces opérations est qu'elles sont indivisibles c'est-à-dire que l'exécution de ces opérations ne peut pas être interrompues.
Un outil sémaphore peut être assimilé à un distributeur de jetons; l'acquisition d'un jeton donnant le droit à un processus
de poursuivre son exécution.
3.1.1 L'opération INIT (Sem, Val)
L'opération INIT a pour but d'initialiser le sémaphore, c'est-à-dire qu'elle met à vide la file d'attente L et initialise
avec la valeur Val le compteur K : on définit ainsi le nombre de jetons initiaux dans le sémaphore.
Init (Sem, Val)
début
masquer_it
Sem. K := Val;
Sem. L := vide;
demasquer_it
fin
3.1.2 L'opération P (Sem)
L'opération P(Sem) "attribue un jeton" au processus appelant si il en reste au moins un et sinon bloque le processus dans
Sem.L. L'opération P est donc une opération éventuellement bloquante pour le processus élu qui l'effectue. Dans le cas du
blocage, il y aura réordonnancement. Concrètement, le compteur K du sémaphore est décrémenté de une unité. Si la valeur du
compteur devient négative, le processus est bloqué.
P (Sem)
début
masquer_it
Sem.K := Sem.K 1;
Si Sem.K < 0
alors
ajouter ce processus à Sem.L
bloquer ce processus
fsi
demasquer_it
fin
3.1.3 L'opération V (Sem)
L'opération V(Sem) a pour but de "rendre un jeton" au sémaphore. De plus, si il y a au moins un processus bloqué dans la file
d'attente L du sémaphore, un processus est réveille. La gestion des réveils s'effectue généralement en mode FIFO (on réveille
le processus le plus anciennement endormi). L'opération V est une opération qui n'est jamais bloquante pour le processus appelant.
V (Sem)
Début
masquer_it
Sem.K := Sem.K + 1;
Si Sem.K <= 0
alors
sortir un processus de Sem.L
réveiller ce processus
fsi
démasquer_it
fin
3.1.4 Signification de la valeur du compteur K
- Si Sem.K > 0, alors Sem.K est le nombre d'opérations P(Sem) passantes
- Si Sem.K <= 0,alors valeur_absolue(Sem.K) est le nombre de processus bloqués dans Sem.L
3.2 Réalisation d'une section critique à l'aide des sémaphores
La réalisation d'une
section critique
à l'aide de l'outil sémaphore s'effectue en utilisant un sémaphore MUTEX, dont le compteur K est initialisé à 1. Le prélude
de la section critique correspond à une opération P(MUTEX). Le postlude de la section critique correspond à une opération
V(MUTEX).
INIT (MUTEX, 1);
P(MUTEX);
Section critique
V(MUTEX)
La figure 2 illustre le fonctionnement de la section critique : Client_1 effectue en premier la demande de réservation : le
P(Mutex) est passant et le "jeton" est alloué au
processus
Client_1. Juste après le test de la valeur de Nb_Place, Client_1 perd donc la main ; Client_2 est élu mais le P(Mutex) est
bloquant : il n'y a plus de jeton disponible dans le compteur du sémaphore. Comme Client_2 est bloqué, Client_1 reprend la
main. Lorsqu'il a achevé sa réservation, Client_1 relâche le jeton par un V(Mutex) : Client_2 est alors réveillé et le jeton
lui est attribué.
 |
Fig 2 : Fonctionnement de la section critique
|
|
Synchronisation entre processus
Exclusion mutuelle
|